package com.fatri.lessionsimple.opengl.drawer

import android.content.Context
import android.graphics.Bitmap
import android.opengl.GLES20
import android.opengl.GLUtils
import com.fatri.lessionsimple.opengl.IDrawer
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer

class BitmapDrawer(val mBitmap: Bitmap ,ctx:Context) :
    IDrawer(ctx) {
    //顶点坐标
    private val mVertexCoors = floatArrayOf(
        -1f, -1f, //(x,y)表示一个坐标，顶点以中心为（0，0）
        1f, -1f,
        -1f, 1f,
        1f, 1f
    )

    //纹理坐标
    private val mTextureCoors = floatArrayOf(
        0f, 1f,  //纹理坐标Android中以左上角为(0，0)
        1f, 1f,
        0f, 0f,
        1f, 0f
    )

    //纹理ID
    private var mTextureID: Int = -1


    //OPENGL 程序ID
    private var mProgram: Int = -1

    //顶点坐标接收者
    private var mVertexPosHandler: Int = -1

    //纹理坐标接收者
    private var mTexturePosHandler: Int = -1

    //新增纹理接收者
    private var mTextureHandler: Int = -1

    private lateinit var mVertexBuffer: FloatBuffer
    private lateinit var mTextureBuffer: FloatBuffer


    init {
        /**
         * 1、初始化定点坐标
         */
        initPos()
    }

    private fun initPos() {
        val bb = ByteBuffer.allocateDirect(mVertexCoors.size * 4)
        bb.order(ByteOrder.nativeOrder())
        //将坐标数据转换未FloatBuffer，传入opengl程序
        mVertexBuffer = bb.asFloatBuffer()
        mVertexBuffer.put(mVertexCoors)
        mVertexBuffer.position(0)

        val cc = ByteBuffer.allocateDirect(mTextureCoors.size * 4)
        cc.order(ByteOrder.nativeOrder())
        mTextureBuffer = cc.asFloatBuffer()
        mTextureBuffer.put(mTextureCoors)
        mTextureBuffer.position(0)
    }

    override fun onDrawFrame() {
        if (mTextureID != -1) {
            /**
             * 2、创建编译并启动OPENGL着色器
             */
            createGLPrg()


            /**
             * 3、激活并绑定纹理单元
             */
            activateTexture()

            /**
             * 绑定图片到纹理单元
             */
            bindBitmapToTexture()
            /**
             * 5、开始渲染
             */
            doDraw()
        }
    }

    override fun onSurfaceCreated() {
    }

    private fun bindBitmapToTexture() {
   if (!mBitmap.isRecycled) {
            //绑定图片到被激活的纹理单元
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0)
        }

    }

    private fun activateTexture() {

        //激活指定纹理单元
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0)  //还有单元TEXTURE1 2
        //绑定纹理ID到纹理单元
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureID)
        //将激活的纹理单元传递到着色器
        GLES20.glUniform1i(mTextureHandler,0) //第二个参数与纹理单元角标对应
        //配置边缘过渡参数
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR.toFloat())//GL_NEAREST（邻近过滤）、GL_LINEAR（线性过滤）
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR.toFloat())

        //环绕方式
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT)

    }

    private fun createGLPrg() {
        if (mProgram == -1) {
            val vertexShaeder = loadShader(GLES20.GL_VERTEX_SHADER, getVertexShader())
            val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, getFragmentShader())

            //创建程序，需要在渲染线程中创建
            mProgram = GLES20.glCreateProgram()
            //顶点着色器加入到程序
            GLES20.glAttachShader(mProgram, vertexShaeder)
            //片元着色器加入到程序
            GLES20.glAttachShader(mProgram, fragmentShader)
            //连接到着色器程序
            GLES20.glLinkProgram(mProgram)

            mVertexPosHandler = GLES20.glGetAttribLocation(mProgram, "aPosition")
            mTexturePosHandler = GLES20.glGetAttribLocation(mProgram, "aCoordinate")
        }

        //使用opengl缓存
        GLES20.glUseProgram(mProgram)
    }

    private fun doDraw() {
        //启用定点的句柄
        GLES20.glEnableVertexAttribArray(mVertexPosHandler)
        GLES20.glEnableVertexAttribArray(mTexturePosHandler)
        //设置着色器参数
        GLES20.glVertexAttribPointer(mVertexPosHandler, 2, GLES20.GL_FLOAT, false, 0, mVertexBuffer)
        GLES20.glVertexAttribPointer(
            mTexturePosHandler,
            2,
            GLES20.GL_FLOAT,
            false,
            0,
            mTextureBuffer
        )


        //开始绘制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
    }




    override fun release() {
        GLES20.glDisableVertexAttribArray(mVertexPosHandler)
        GLES20.glDisableVertexAttribArray(mTexturePosHandler)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)
        GLES20.glDeleteTextures(1, intArrayOf(mTextureID), 0)
        GLES20.glDeleteProgram(mProgram)

    }

    override fun onSurfaceChanged(width: Int, height: Int) {

    }

    private fun getVertexShader(): String {
//        return "attribute vec4 aPosition;" +
//                "void main() {" +
//                "  gl_Position = aPosition;" +
//                "}"

        return "attribute vec4 aPosition;" +        //顶点坐标，aPosition由创建program时指定
                "attribute vec2 aCoordinate;" +     //纹理坐标
                "varying vec2 vCoordinate;" +
                "void main() {" +
                "  gl_Position = aPosition;" +
                "  vCoordinate = aCoordinate;" +      //用于传递纹理坐标给片元着色器，命名和片元着色器中的一致
                "}"
    }

    private fun getFragmentShader(): String {
//        return "precision mediump float;" +
//                "void main() {" +
//                "  gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);" +  //RGBA
//                "}"

        return "precision mediump float;" +         //配置float精度
                "uniform sampler2D uTexture;" +     //从Java传递进入来的纹理单元
                "varying vec2 vCoordinate;" +       //从顶点着色器传递进来的纹理坐标
                "void main() {" +
                "  vec4 color = texture2D(uTexture, vCoordinate);" +
                "  gl_FragColor = color;" +
                "}"
    }


}